package com.taijihuabao.modules.service.impl;

import cn.hutool.core.util.IdUtil;
import com.alibaba.druid.util.StringUtils;
import com.github.pagehelper.PageHelper;
import com.taijihuabao.common.commonutils.FileInOutPutStreamUtil;
import com.taijihuabao.common.emailutils.EmailPojo;
import com.taijihuabao.common.exception.ServiceException;
import com.taijihuabao.common.jsonresult.ApplicationResponseCode;
import com.taijihuabao.common.commonutils.JwtTokenUtil;
import com.taijihuabao.common.commonutils.Md5Utils;
import com.taijihuabao.common.commonutils.PageResult;
import com.taijihuabao.common.rabbitmq.RabbitMqProducer;
import com.taijihuabao.common.commonutils.RandomValidateCodeUtil;
import com.taijihuabao.common.redisconfig.UserLoad;
import com.taijihuabao.modules.entity.*;
import com.taijihuabao.modules.mapper.*;
import com.taijihuabao.modules.model.basedto.IdDTO;
import com.taijihuabao.modules.model.basedto.EmailAddressDTO;
import com.taijihuabao.modules.model.basedto.FileDTO;
import com.taijihuabao.modules.model.menu.vo.MenuInfoVO;
import com.taijihuabao.modules.model.user.dto.*;
import com.taijihuabao.modules.model.user.vo.UserInfoVO;
import com.taijihuabao.modules.model.user.vo.UserLoginVO;
import com.taijihuabao.modules.model.user.vo.UserSelectorVO;
import com.taijihuabao.modules.service.UserService;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.collections4.CollectionUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.userdetails.User;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.core.userdetails.UsernameNotFoundException;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletResponse;
import java.time.Duration;
import java.util.*;

/**
 * @author 用户管理
 */
@Service
@Slf4j
public class UserServiceImpl implements UserService {

    /**
     * 常量
     */
    private static final String USER_LOGIN_CODE_PREFIX = "LoginVailCode-";
    private static final String USER_REGISTER_CODE_PREFIX = "RegisterVailCode-";
    private static final String USER_FORGET_CODE_PREFIX = "ForgetVailCode-";
    private static final String RESEND_MESSAGE_PREFIX = "ResendMessage-";
    private final Long OUT_TIME = 30L;
    private final String USER_PROFILE_PATH = "/root/images/profiles/";
    private final Long LOGIN_VAIL_CODE = IdUtil.getSnowflake(0, 0).nextId();

    @Autowired
    RedisTemplate<String, Object> redisTemplate;
    @Resource
    private UserMapper userMapper;
    @Resource
    private UserRoleMapper userRoleMapper;
    @Resource
    private RoleMapper roleMapper;
    @Resource
    private RabbitMqProducer rabbitMqProducer;
    @Resource
    private MenuMapper menuMapper;
    @Resource
    private MenuRoleMapper menuRoleMapper;
    @Resource
    private DeptUserMapper deptUserMapper;
    @Resource
    private DeptRoleMapper deptRoleMapper;
    @Resource
    private DeptMapper deptMapper;

    @Override
    public void getLoginVailCodeImg(HttpServletResponse response) {
        //生成图片
        RandomValidateCodeUtil.getRandcode(response);
        //获取验证码
        String vailCode = RandomValidateCodeUtil.getFinalCode();
        //存入redis
        redisTemplate.opsForValue().set(USER_LOGIN_CODE_PREFIX + LOGIN_VAIL_CODE, vailCode, Duration.ofMinutes(OUT_TIME));
    }

    @Override
    public UserLoginVO login(UserLoginDTO loginDTO) {
        if (StringUtils.isEmpty(loginDTO.getUsername()) || StringUtils.isEmpty(loginDTO.getPassword())) {
            throw new ServiceException(ApplicationResponseCode.USER_PASS_NOT_NULL);
        }
        if (StringUtils.isEmpty(loginDTO.getVailCode()) || !loginDTO.getVailCode().equalsIgnoreCase((String) redisTemplate.opsForValue().get(USER_LOGIN_CODE_PREFIX + LOGIN_VAIL_CODE))) {
            throw new ServiceException(ApplicationResponseCode.VAIL_CODE_ERROR);
        }
        //使用MD5加密比对
        String encryPass = Md5Utils.encrypt(loginDTO.getPassword());
        //将前端dto数据，放入UserEntity中
        UserEntity userEntity = new UserEntity();
        userEntity.setUsername(loginDTO.getUsername());
        userEntity.setPassword(encryPass);
        UserEntity user = userMapper.login(userEntity);
        UserLoginVO userLoginVO;
        if (user != null) {
            //是否重复登录
            Set<String> keys = redisTemplate.keys("UserLogin*");
            if (!com.alibaba.excel.util.CollectionUtils.isEmpty(keys)) {
                for (String key : keys) {
                    //String类型的键值获取
                    UserEntity value = (UserEntity) redisTemplate.opsForValue().get(key);
                    if (value != null) {
                        if (user.getId().equals(value.getId())) {
                            redisTemplate.opsForValue().getOperations().delete(key);
                        }
                    }
                }
            }
            //使用登录成功用户的信息生成token
            String token = "UserLogin" + JwtTokenUtil.createToken(user);
            redisTemplate.opsForValue().set(token, user, Duration.ofMinutes(OUT_TIME));
            //拿到登录用户的信息
            UserInfoVO userInfoVO = selectById(user.getId());
            userLoginVO = new UserLoginVO();
            userLoginVO.setToken(token);
            userLoginVO.setUserInfoVO(userInfoVO);
            //用户头像路径
            userInfoVO.setProfile(userMapper.userProfilePathQuery(user.getId()));
        } else {
            throw new ServiceException(ApplicationResponseCode.USER_OR_PASSWORD_ERROR);
        }
        return userLoginVO;
    }

    @Override
    public void registerVailCode(EmailAddressDTO emailAddressDTO) {
        EmailPojo emailPojo = new EmailPojo();
        List<String> emailList = new ArrayList<>();
        emailList.add(emailAddressDTO.getEmail());
        emailPojo.setReceiver(emailList);
        rabbitMqProducer.mailRegisterVailCodeSend(emailPojo);
        redisTemplate.opsForValue().set(USER_REGISTER_CODE_PREFIX + emailList.get(0), RabbitMqProducer.REGISTER_VAIL_CODE, Duration.ofMinutes(RabbitMqProducer.OUT_TIME));
    }

    @Override
    public void register(UserRegisterDTO registerDTO) {
        if (StringUtils.isEmpty(registerDTO.getUsername()) || StringUtils.isEmpty(registerDTO.getPassword())) {
            throw new ServiceException(ApplicationResponseCode.USER_PASS_NOT_NULL);
        }
        if (userMapper.isExistUserName(registerDTO.getUsername()) != null) {
            throw new ServiceException(ApplicationResponseCode.USER_HAS_EXISTED);
        }
        if (StringUtils.isEmpty(registerDTO.getName())) {
            throw new ServiceException(ApplicationResponseCode.USER_NAME_NOT_NULL);
        }
        if (registerDTO.getPhone() == null) {
            throw new ServiceException(ApplicationResponseCode.USER_PHONEMES_NOTNULL);
        }
        if (userMapper.isPhoneRepeat(registerDTO.getPhone()) != null) {
            throw new ServiceException(ApplicationResponseCode.USER_HAS_EXISTED);
        }
        if (StringUtils.isEmpty(registerDTO.getEmail())) {
            throw new ServiceException(ApplicationResponseCode.USER_EMAIL_NOTNULL);
        }
        if (userMapper.isEmailRepeat(registerDTO.getEmail()) != null) {
            throw new ServiceException(ApplicationResponseCode.USER_HAS_EXISTED);
        }
        if (registerDTO.getVerificationCode() == null || !Objects.equals(redisTemplate.opsForValue().get(USER_REGISTER_CODE_PREFIX + registerDTO.getEmail()), registerDTO.getVerificationCode())
                && !Objects.equals(redisTemplate.opsForValue().get(RESEND_MESSAGE_PREFIX + registerDTO.getEmail()), registerDTO.getVerificationCode())) {
            throw new ServiceException(ApplicationResponseCode.USER_EMAIL_CODE_FALSE);
        }
        //使用MD5加密比对
        String encryPass = Md5Utils.encrypt(registerDTO.getPassword());
        //将前端dto数据，放入UserEntity中
        UserEntity userEntity = new UserEntity();
        userEntity.setUsername(registerDTO.getUsername());
        userEntity.setPassword(encryPass);
        userEntity.setName(registerDTO.getName());
        userEntity.setSex(registerDTO.getSex());
        userEntity.setPhoneNumber(registerDTO.getPhone());
        userEntity.setUserEmail(registerDTO.getEmail());
        userMapper.insert(userEntity);
        //注册默认角色--用户
//        userRole.insert(new UserRoleEntity(userEntity.getId(), 3L));
    }

    @Override
    public void updPass(UserUpPassDTO upPassDTO) {
        UserEntity userEntity = UserLoad.getUser();
        //查询数据库老密码
        UserInfoVO user = userMapper.selectById(userEntity.getId());
        if (user == null) {
            throw new ServiceException(ApplicationResponseCode.ID_NOTNULL);
        }
        //MD5不可逆 加密输入的老密码对比
        String encryPass = Md5Utils.encrypt(upPassDTO.getOldPass());
        if (encryPass.equals(user.getPassword())) {
            //加密新数据
            String newPass = Md5Utils.encrypt(upPassDTO.getPassword());
            userEntity.setPassword(newPass);
            userMapper.updPass(userEntity);
        } else {
            throw new ServiceException(ApplicationResponseCode.USER_OLD_PASSWORD);
        }
    }

    @Override
    public void forgetLoginVailCode(EmailAddressDTO emailAddressDTO) {
        if (userMapper.forgetPassVerify(emailAddressDTO.getEmail()) == null) {
            throw new ServiceException(ApplicationResponseCode.USER_ACCOUNT_NOT_REGISTER);
        }
        EmailPojo emailPojo = new EmailPojo();
        List<String> emailList = new ArrayList<>();
        emailList.add(emailAddressDTO.getEmail());
        emailPojo.setReceiver(emailList);
        rabbitMqProducer.mailForgetVailCodeSend(emailPojo);
        redisTemplate.opsForValue().set(USER_FORGET_CODE_PREFIX + emailList.get(0), RabbitMqProducer.FORGET_VAIL_CODE, Duration.ofMinutes(RabbitMqProducer.OUT_TIME));
    }

    @Override
    public void forgetVailCodeVerify(UserEmailVailCodeDTO emailVailCodeDTO) {
        if (emailVailCodeDTO.getVailCode() == null || !Objects.equals(redisTemplate.opsForValue().get(USER_FORGET_CODE_PREFIX + emailVailCodeDTO.getEmail()), emailVailCodeDTO.getVailCode())
                && !Objects.equals(redisTemplate.opsForValue().get(RESEND_MESSAGE_PREFIX + emailVailCodeDTO.getEmail()), emailVailCodeDTO.getVailCode())) {
            throw new ServiceException(ApplicationResponseCode.USER_EMAIL_CODE_FALSE);
        }
    }

    @Override
    public void forgetPassRepeat(UserForgetPassDTO forgetPassDTO) {
        if (StringUtils.isEmpty(forgetPassDTO.getUsername()) || StringUtils.isEmpty(forgetPassDTO.getPassword())) {
            throw new ServiceException(ApplicationResponseCode.USER_PASS_NOT_NULL);
        }
        UserEntity userEntity = new UserEntity();
        userEntity.setUsername(forgetPassDTO.getUsername());
        userEntity.setPassword(Md5Utils.encrypt(forgetPassDTO.getPassword()));
        userMapper.repeatPass(userEntity);
    }

    @Override
    public PageResult selectList(UserListFromDTO listDTO) {
        PageHelper.startPage(listDTO.getPage(), listDTO.getSize());
        UserEntity userEntity = new UserEntity();
        userEntity.setUsername(listDTO.getUsername());
        userEntity.setName(listDTO.getName());
        userEntity.setSex(listDTO.getSex());
        List<UserInfoVO> infoVos = userMapper.selectList(userEntity);
        for (UserInfoVO userInfoVO : infoVos) {
            List<DeptUserEntity> deptUserEntitys = deptUserMapper.selectDeptByUserId(userInfoVO.getId());
            if (!CollectionUtils.isEmpty(deptUserEntitys)) {
                DeptUserEntity deptuser = deptUserEntitys.get(0);
                if (!Objects.isNull(deptuser)) {
                    if (!Objects.isNull(deptMapper.selectDeptByCode(deptuser.getDeptCode()))) {
                        String deptName = deptMapper.selectDeptByCode(deptuser.getDeptCode()).getDeptName();
                        userInfoVO.setDeptName(deptName);
                    }
                }
                List<String> deptRoles = new ArrayList<>();
                for (DeptUserEntity deptUserEntity : deptUserEntitys) {
                    if (!StringUtils.isEmpty(deptUserEntity.getDeptRole())) {
                        String deptRole = deptUserEntity.getDeptRole();
                        if (!Objects.isNull(deptRoleMapper.selectDeptByRoleName(deptRole))) {
                            DeptRoleEntity role = deptRoleMapper.selectDeptByRoleName(deptRole);
                            if (!Objects.isNull(role)) {
                                String roleName = role.getRoleName();
                                deptRoles.add(roleName);
                            }
                        }
                    }
                }
                userInfoVO.setDeptRoles(deptRoles);
            }

        }
        return new PageResult(infoVos);
    }

    @Override
    public List<UserSelectorVO> userSelector() {
        return userMapper.userSelector();
    }

    @Override
    public UserInfoVO selectById(Long id) throws ServiceException {
        List<MenuInfoVO> fatherMenus = new ArrayList<>();
        List<MenuRoleEntity> UserMenus = new ArrayList<>();
//        //拿到当前用户菜单
//        UserInfoVO userInfoVO = userMapper.selectUserMenu(id);
//        List<MenuInfoVO> menus = userInfoVO.getMenus();
//        for (MenuInfoVO menuInfoVO : menus) {
//            if (menuInfoVO.getParentId() == 0){
//                fatherMenus.add(menuInfoVO);
//            }
//        }
        //拿到当前用户的角色信息
        List<UserRoleEntity> userRoleEntities = userRoleMapper.selectByUid(id);
        UserInfoVO userVO = null;
        //判断角色信息为空
        if (CollectionUtils.isEmpty(userRoleEntities)) {
            //只查用户的信息
            userVO = userMapper.selectById(id);
        }else {
            //拿到用户角色菜单信息
            for (UserRoleEntity userRoleEntity : userRoleEntities) {
                List<MenuRoleEntity> menuRoleEntities = menuRoleMapper.selectByRoleId(userRoleEntity.getRid());
                for (MenuRoleEntity menuRoleEntity : menuRoleEntities){
                    UserMenus.add(menuRoleEntity);
                }
            }
            //判断用户角色有没有菜单
            if (!CollectionUtils.isEmpty(UserMenus)) {
                //查用户信息以及角色信息菜单信息
                userVO = userMapper.selectByIdRole(id);
                List<MenuInfoVO> menus = userVO.getMenus();
                for (MenuInfoVO menuInfoVO : menus) {
                    if (menuInfoVO.getParentId() == 0) {
                        MenuInfoVO menuInfoV01 = menuMapper.selectById(menuInfoVO.getId());
                        fatherMenus.add(menuInfoV01);
                    }
                }
                userVO.setMenus(fatherMenus);
            }else {
                userVO = userMapper.selectById(id);
            }
        }
        if (Objects.isNull(userVO)) {
            throw new ServiceException(ApplicationResponseCode.USER_NOT_EXIST);
        }
        return userVO;
    }

    @Override
    @Transactional(propagation = Propagation.REQUIRED, rollbackFor = Exception.class)
    public void insert(UserCrFromDTO crFromDTO) {
        if (StringUtils.isEmpty(crFromDTO.getUsername()) || StringUtils.isEmpty(crFromDTO.getPassword())) {
            throw new ServiceException(ApplicationResponseCode.USER_PASS_NOT_NULL);
        }
        if (userMapper.isExistUserName(crFromDTO.getUsername()) != null) {
            throw new ServiceException(ApplicationResponseCode.USER_HAS_EXISTED);
        }
        if (StringUtils.isEmpty(crFromDTO.getName())) {
            throw new ServiceException(ApplicationResponseCode.USER_NAME_NOT_NULL);
        }
        if (crFromDTO.getPhone() == null) {
            throw new ServiceException(ApplicationResponseCode.USER_PHONEMES_NOTNULL);
        }
        if (userMapper.isPhoneRepeat(crFromDTO.getPhone()) != null) {
            throw new ServiceException(ApplicationResponseCode.USER_HAS_EXISTED);
        }
        if (StringUtils.isEmpty(crFromDTO.getEmail())) {
            throw new ServiceException(ApplicationResponseCode.USER_EMAIL_NOTNULL);
        }
        if (userMapper.isEmailRepeat(crFromDTO.getEmail()) != null) {
            throw new ServiceException(ApplicationResponseCode.USER_HAS_EXISTED);
        }
        //获取创建人，创建时间
        UserEntity userEntity = new UserEntity();
        userEntity.setUsername(crFromDTO.getUsername());
        userEntity.setName(crFromDTO.getName());
        userEntity.setSex(crFromDTO.getSex());
        userEntity.setPhoneNumber(crFromDTO.getPhone());
        userEntity.setUserEmail(crFromDTO.getEmail());
        userEntity.setPassword(Md5Utils.encrypt(crFromDTO.getPassword()));
        userMapper.insert(userEntity);
        //通过账号查询新增的用户id
        UserEntity forUserId = userMapper.isExistUserName(userEntity.getUsername());
        //查找所有角色
        List<Long> roleId = roleMapper.findRoleId();
        if (!CollectionUtils.isEmpty(crFromDTO.getRids())) {
            //用户授权，rid都存在就都添加，只要有一个不存在就插不进去
            for (Long rid : crFromDTO.getRids()) {
                if (roleId.contains(rid)) {
                    userRoleMapper.insert(new UserRoleEntity(forUserId.getId(), rid));
                } else {
                    throw new ServiceException(ApplicationResponseCode.ROLE_P_NONEXISTENT);
                }
            }
        }
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void update(UserUpFromDTO upFromDTO) {
        UserInfoVO userInfoVO = userMapper.selectById(upFromDTO.getId());
        if (Objects.isNull(userInfoVO)) {
            throw new ServiceException(ApplicationResponseCode.ID_NOTNULL);
        }
        if (upFromDTO.getPhone() == null) {
            throw new ServiceException(ApplicationResponseCode.USER_PHONEMES_NOTNULL);
        }
        if (StringUtils.isEmpty(upFromDTO.getEmail()) || "".equals(upFromDTO.getEmail())) {
            throw new ServiceException(ApplicationResponseCode.USER_EMAIL_NOTNULL);
        }
        //修改用户信息
        UserEntity userEntity = new UserEntity();
        userEntity.setId(upFromDTO.getId());
        userEntity.setSex(upFromDTO.getSex());
        userEntity.setPhoneNumber(upFromDTO.getPhone());
        userEntity.setUserEmail(upFromDTO.getEmail());
        userEntity.setName(upFromDTO.getName());
        System.out.println(userEntity);
        //修改不存在的用户提示
        List<Long> id = userMapper.findId();
        if (!id.contains(upFromDTO.getId())) {
            throw new ServiceException(ApplicationResponseCode.USER_NOT_EXIST);
        }
        userMapper.update(userEntity);
        //授权,清空用户角色并重新添加
        UserRoleEntity userRoleEntity = new UserRoleEntity();
        userRoleEntity.setUid(upFromDTO.getId());
        userRoleMapper.delRidByUid(userRoleEntity);
        //给用户添加角色
        List<Long> roleId = roleMapper.findRoleId();
        //传入的rid进行判断
        if (!CollectionUtils.isEmpty(upFromDTO.getRids())) {
            for (Long rid : upFromDTO.getRids()) {
                if (roleId.contains(rid)) {
                    userRoleMapper.insert(new UserRoleEntity(upFromDTO.getId(), rid));
                } else {
                    throw new ServiceException(ApplicationResponseCode.ROLE_P_NONEXISTENT);
                }
            }
        }
    }

    @Override
    public void delete(IdDTO dto) {
        UserEntity userEntity = new UserEntity();
        userEntity.setId(dto.getId());
        if (Objects.isNull(userMapper.selectById(dto.getId()))) {
            throw new ServiceException(ApplicationResponseCode.ID_NOTNULL);
        }
        //删除没有的用户进行提示
        List<Long> list = userMapper.findId();
        if (!list.contains(dto.getId())) {
            throw new ServiceException(ApplicationResponseCode.USER_NOT_EXIST);
        }
        userMapper.delete(userEntity);
    }

    @Override
    public List<Map<String, Object>> getAllRedisVal() {
        List<Map<String, Object>> list = new ArrayList<>();
        //key("*") 获取所有键
        Set<String> keys = redisTemplate.keys("UserLogin*");
        for (String key : keys) {
            HashMap<String, Object> map = new HashMap<>(keys.size());
            //String类型的键值获取
            Object value = redisTemplate.opsForValue().get(key);
            map.put("key", key);
            map.put("value", value);
            list.add(map);
        }
        return list;
    }

    /**
     * 验证用户
     *
     * @param userId
     * @return
     * @throws UsernameNotFoundException
     */
    @Override
    public UserDetails loadUserByUsername(String userId) throws UsernameNotFoundException {
        UserInfoVO userEntity = userMapper.selectById(Long.valueOf(userId));
        if (userEntity != null) {
            //创建角色集合对象
            Collection<GrantedAuthority> authorities = new ArrayList<>();
           /* GrantedAuthority grantedAuthority = new SimpleGrantedAuthority("ROLE_ACTIVITI_USER");
            authorities.add(grantedAuthority);*/
            User user = new User(userEntity.getUsername(), "password", authorities);
            return user;
        }
        return null;
    }

    @Override
    public String userProfilePathQuery() {
        return userMapper.userProfilePathQuery(UserLoad.getUser().getId());
    }

    @Override
    public void addUserProfile(FileDTO fileDTO) {
        FileInOutPutStreamUtil.uploadFile(fileDTO.getFile(), USER_PROFILE_PATH);
        String filePath = FileInOutPutStreamUtil.getFilePathForData();
        UserEntity userEntity = new UserEntity();
        userEntity.setId(UserLoad.getUser().getId());
        userEntity.setUserProfile(filePath);
        userMapper.addUserProfile(userEntity);
    }

}
